package grammer

import (
	"fmt"
	"math"
	"reflect"
	"unicode/utf8"
	"unsafe"
)

func variable_type() {
	// int uint uinptr 和平台有关
	// 编写有移植性要求的代码时, 千万不要强依赖这些类型的长度
	var a, b = int(5), uint(6)
	var p uintptr = 0x12345678
	fmt.Println("signed integer a's length is", unsafe.Sizeof(a))   // 8
	fmt.Println("unsigned integer b's length is", unsafe.Sizeof(b)) // 8
	fmt.Println("unintptr's length is", unsafe.Sizeof(p))           // 8

	// 整数溢出
	var s int8 = 127
	s += 1 // 预期128, 实际结果-128

	var u uint8 = 1
	u -= 2 // 预期-1, 实际结果255

	// 字面量
	a = 53         // 十进制
	b = 0700       // 八进制, 已"0"为前缀
	c1 := 0xaabbcc // 十六进制, 以"0x"为前缀
	c2 := 0xddeeff // 十六进制, 以"0X"为前缀
	// Go 1.13 增加了对二进制字面量的支持
	d1 := 0b10000001 // 二进制, 以"0b"为前缀
	d2 := 0b10000001 // 二进制, 以"0b"为前缀
	e1 := 0o700      // 八进制, 以"0o"为前缀
	e2 := 0o700      // 八进制, 以"0O"为前缀

	// 还可以通过分隔符"_"提高可读性
	a = 5_3
	b = 0b_1000_0111
	c1 = 0_700
	c2 = 0o_700
	d1 = 0x_5c_6d

	// 格式化输出
	fmt.Printf("%b\n", c1) // 输出二进制
	fmt.Printf("%d\n", c2) // 输出十进制
	fmt.Printf("%o\n", d1) // 输出八进制
	fmt.Printf("%O\n", d2) // 输出八进制(带0o前缀)
	fmt.Printf("%x\n", e1) // 输出十六进制(小写)
	fmt.Printf("%X\n", e2) // 输出十六进制(大写)

	// 浮点类型			符号位(bit位数)		阶码(bit位数)			阶码偏移值		尾数(bit位数)
	// 单精度(float32)	1					8						127			23
	// 双精度(float64)	1					11						1023		52
	/**
	 * (-1)<sub>S</sub> X 1.M X 2<sub>E-offset</sub>
	 * S->符号位sign
	 * M->尾数 maintissa
	 * E->阶码 exponent
	 **/
	// 使用float32来表示 139.8125
	// 139.8125=10001011.1101b(转换二进制)
	// 移动小数点, 直到证书部分仅有一个1  10001011.1101b = 1.00010111101b X 10b<sub>7</sub>, 尾数就是 00010111101b
	// 计算阶码: 7 + 127 = 134 = 10000110b
	// 符号位:0, 阶码 10000110 尾数(不足23位, 向后补0) 00010111101000000000000
	var f float32 = 139.8125
	fmt.Printf("%b\n", math.Float32bits(f)) //1000011000010111101000000000000, 填上符号位0后, 和推导没有差别

	// 字面值
	// 3.1415 .15(整数部分如果为0, 整数部分可以省略不写) 81.80 82.(小数部分如果为0, 小数点后的0可以省略不写)
	// 6674.28e-2 (6672.28 * 10^(-2) = 66.7428) .12345E+5 (0.12345*10^(5)=12345.000000)
	// 十六进制科学计数法
	// 0x2.p10 // 2.0 * 2^10 = 2048.0000000
	// 0x1.Fp+0 // 1.9375 * 2^0 = 1.93750000
	// 十六进制科学计数法的整数、小数部分用的都是十六进制形式, 但指数部分依然是十进制形式, 并且字面值中的p/P代表的幂运算的底数为2
	f = 123.45678
	fmt.Printf("%f\n", f) // 普通十进制输出
	fmt.Printf("%e\n", f) // 1.2345678e+02
	fmt.Printf("%x\n", f) // 0x1.edd3be22e5de1p+06

	// Go 原生支持两种复数类型 complex64 和 complex128
	// complex64 的实部与虚部都是float32类型
	// complex128 的实部与虚部都是float64类型

	c := 5 + 6i
	d := 0o123 + .12345e+5i       // 83 + 12345i
	c = complex(5, 6)             // 5 + 6i
	d = complex(0o123, .12345e+5) // 83 + 12345i
	// Go 题哦那个的预定义的函数real和imag, 来获取一个复数的实部和虚部, 返回值时一个浮点类型
	r := real(d) // 83
	i := imag(c) // 6

	fmt.Println(r, i)

	// 创建自定义的数值类型
	type MyInt int32
	var m int = 5
	var n int32 = 6
	// var a MyInt = m   错误: 在赋值中不能将m(int类型)作为MyInt类型使用
	// var a MyInt = n   错误: 在赋值中不能将m(int32类型)作为MyInt类型使用
	// 显示转型
	var a_ MyInt = MyInt(m) // ok
	a_ = MyInt(n)

	fmt.Println(a_)
}

func main() {
	fmt.Println("Hello World!")

	variable_type()

	string_type()
}

func string_type() {
	// go 字符串多行
	var s string = `         ,_---~~~~~----._
			_,,_,*^____      _____*g*\"*,--,
		/ __/ /'     ^.  /      \ ^@q   f
		[  @f | @))    |  | @))   l  0 _/
		\/   \~____ / __ \_____/     \
			|           _l__l_           I
			}          [______]           I
			]            | | |            |
			]             ~ ~             |
			|                            |
			|                           |`
	fmt.Println(s)

	s = "中国人"
	fmt.Printf("the length of s = %d\n", len(s)) // 9
	for i := 0; i < len(s); i++ {
		fmt.Printf("0x%x", s[i]) // 0xe4 0xb8 0xad 0xe5 0x9b 0xbd 0xe4 0xba 0xba
	}
	fmt.Printf("\n")

	encodeRune()
	decodeRune()

	s = "hello"
	hdr := (*reflect.StringHeader)(unsafe.Pointer(&s)) // 将string类型变量地址显式转型为reflect.StringHeader
	fmt.Printf("0x%x\n", hdr.Data)                     // 0x10a30e0
	p := (*[5]byte)(unsafe.Pointer(hdr.Data))          // 获取Data字段所指向的数组的指针
	dumpBytesArray((*p)[:])                            // [h e l l o ] // 输出底层数组的内容
}

// 使用 Go 在标准库中提供的 UTF-8 包，对 Unicode 字符（rune）进行编解码
// rune -> []byte
func encodeRune() {
	var r rune = 0x4E2D
	fmt.Printf("the unicode charactor is %c\n", r) // 中
	buf := make([]byte, 3)
	_ = utf8.EncodeRune(buf, r)                       // 对rune进行utf-8编码
	fmt.Printf("utf-8 representation is 0x%X\n", buf) // 0xE4B8AD
}

// []byte -> rune
func decodeRune() {
	var buf = []byte{0xE4, 0xB8, 0xAD}
	r, _ := utf8.DecodeRune(buf)                                                             // 对buf进行utf-8解码
	fmt.Printf("the unicode charactor after decoding [0xE4, 0xB8, 0xAD] is %s\n", string(r)) // 中
}

func dumpBytesArray(arr []byte) {
	fmt.Printf("[")
	for _, b := range arr {
		fmt.Printf("%c ", b)
	}
	fmt.Printf("]\n")
}
